/* Sentinel - IRC Statistical and Operator Services
** tld.c - TLD management functions
**
** Copyright W. Campbell and others.  See README for more details
** Some code Copyright: Jonathan George, Kai Seidler, ircd-hybrid Team,
**                      IRCnet IRCD developers.
**
** $Id: tld.c,v 1.30 2003/12/06 00:27:23 wcampbel Exp $
*/

#include "stats.h"
#include "struct.h"
#include "proto.h"
#include "slog.h"
#include "mem.h"

struct TLD *tldlist[T_TABLE_SIZE];
static struct TLD *tld_unknown;
static struct TLD *tld_num;
static struct TLD *tld_ipv6;

static void add_tld_to_hash_table(char *, struct TLD*);

/* "net" -- not DOT"net" */
struct TLD *findtld(char *tld)
{
  struct TLD *t;

  t = tldlist[HASH((unsigned char *) tld, T_TABLE_SIZE)];
  while (t && (strcasecmp(tld, t->tld) != 0))
    t = t->next;

  return t;
}

/* Add the TLD entry to a user record */
struct TLD *AddTLD(struct User *u)
{
  struct TLD *t = NULL;
  char *m;

  m = strchr(u->hostname, ':');

  if (m != NULL)
  {
    t = tld_ipv6;
  }
  else
  {

    m = strrchr(u->hostname, '.');

    if (m == NULL)
      t = tld_unknown;
    else
      m++;

    /* I think this is right...for hostnames such as "Internet." */
    if (!m)
    {
      slog(DEFAULT_LOG, L_NOTICE, "NULL TLD from %s (%s)", u->nick,
           u->hostname);
      t = tld_unknown;
    }

    if (!t)
    {
      if (!isdigit((int) *m))
        t = findtld(m);
      else
        t = tld_num;
    }
  }

  if (!t)
  {
    if (!IsIgnoreIllegalTLD())
    {
      slog(DEFAULT_LOG, L_NOTICE, "Unable to find TLD entry for %s (%s)",
           u->nick, m);
      spy("Invalid TLD entry for %s (%s)", u->nick, m);
      sendto_dcc_flag(CF_TLD, "Invalid TLD entry for %s (%s)",
                      u->nick, m);
    }
    t = tld_unknown;
  }
  t->users++;

  return t;
}

/* Load the TLD file */
void LoadTLD()
{
  FILE *fp;
  char buf[BUFSIZE];
  char *tmp = NULL;
  char *tmp2 = NULL;
  char *native = NULL;
  struct TLD *t;
  int i;

  if ((fp = fopen(TLD_FILE, "r")) == NULL)
  {
    slog(DEFAULT_LOG, L_CRIT, "Top Level Domain Statistics not loaded: %s",
         strerror(errno));
    fprintf(stderr, "Top Level Domain Statistics not loaded: %s",
            strerror(errno));
    close_logfiles();
    exit(4);
    /* NOT REACHED */
    return ;
  }

  for (i = 0; i < T_TABLE_SIZE; i++)
    tldlist[i] = NULL;

  while (fgets(buf, BUFSIZE, fp))
  {
    tmp = strchr(buf, '\t');
    *tmp = '\0';
    tmp++;
    native = strchr(tmp, '\t');
    if (native != NULL)
    {
      *native = '\0';
      native++;
      tmp2 = strchr(native, '\n');
      if (tmp2)
        *tmp2 = '\0';
      tmp2 = strchr(native, '\r');
      if (tmp2)
        *tmp2 = '\0';
    }
    else
    {
      tmp2 = strchr(tmp, '\n');
      if (tmp2)
        *tmp2 = '\0';
      tmp2 = strchr(tmp, '\r');
      if (tmp2)
        *tmp2 = '\0';
    }

    /* This should be block allocated */
    t = smalloc(sizeof(struct TLD));
    memcounts.tld++;
    /* t->users = 0; - memset */
    strlcpy(t->country, tmp, LINE);
    strlcpy(t->tld, buf, MAXTLD);
    if (native != NULL)
    {
      t->native = sstrdup(native);
      /* +1 for the \0 */
      memcounts.native++;
      memcounts.nativemem += strlen(t->native) + 1;
    }
    /* memset */

    add_tld_to_hash_table(t->tld, t);
  }
  fclose(fp);
}

static void add_tld_to_hash_table(char *key, struct TLD* t)
{
  t->hash = HASH((unsigned char *) key, T_TABLE_SIZE);
  t->next = tldlist[t->hash];
  tldlist[t->hash] = t;
}

void init_tld()
{
  struct TLD *t;
  int i;

  for (i = 0; i < T_TABLE_SIZE; i++)
  {
    for (t = tldlist[i]; t; t = t->next)
    {
      t->users = 0;
    }
  }

  tld_unknown = findtld("unknown");
  tld_num = findtld("num");
  tld_ipv6 = findtld("ipv6");
}
